/*
 *	Author: 		Jess Nielsen (jess.nielsen@ementor.dk)
 *	Revision date:	2. marts 2004
 *	Revision:		1.0
 *
 *	Copyright 2004 Jess Nielsen
 */

#include "stdafx.h"

#include <iostream>
#include <fstream>
#include <sstream>

#include <stdio.h>
#include <string.h>
#include <iostream.h>
#include <comutil.h>
#include <windows.h>
#include <io.h>
#include <list>
#include <iterator>

#include "Shlwapi.h"

char HEADERFILE[MAX_PATH] = "c:\\1\\header.txt";
bool NOHEADER = FALSE;

std::list<std::string> names;
std::list<std::string> values;

void PrintHelp()
{
	std::string s = "";
	s += "Utility that adds a header text to a bundle of source files\n";
	s += "Usage:\n";
	s += "AddHeader \t-basedir c:\\source\\*.h -headerdir c:\\conf\\header.txt | noheader [-help]\n";
	s += "\t\t[-params c:\\conf\\keywords.txt]\n";
	s += "Arguments:\n";
	s += "-basedir \t\tdirectory that contains source files including file type\n";
	s += "-headerdir \tfull path to the header file or 'noheader' if only keywords should be modified\n";
	s += "-params \t\tfull path to parameter file (optional)\n";
//	s += "-r \t\trecursive (optional)\n";
	s += "-help \t\tthis help screen (optional)\n";
	s += "\n";
	s += "Programmed by:\n";
	s += "\t\tJess Nielsen\n";

	MessageBox(NULL, (char*)s.c_str(), "AddHeader HelpScreen", MB_OK);
}

void get_FileSize(FILE *stream, long* size)
{
	long
		curpos = 0L,
		length = 0L;

	curpos = ftell(stream);
	fseek(stream, 0L, SEEK_END);
	length = ftell(stream);
	fseek(stream, curpos, SEEK_SET);

	*size = length;
}

int ParseParameters(const char *fileName)
{
	FILE * fp = NULL;
	long size = 0;

	fp = fopen(fileName, "rb");
	if (NULL == fp)
		return -1;

	get_FileSize(fp, &size);
	if (0 >= size)
		return -1;

	char *data = (char*)malloc(size+1);
	data[size] = 0;
	fread(data, 1, size, fp);
	fclose(fp);

	int pos = -1;
	std::string filedata = data;
	free(data);

	while (-1 < (pos = filedata.find(";"))) {
		std::string pair = filedata.substr(0, pos);
		std::string value, name;
		int innerpos = pair.find(",");

		name = pair.substr(0, innerpos);
		value = pair.substr(innerpos +1, pair.length()-1);

		names.push_back(name);
		values.push_back(value);

		filedata = filedata.substr(pos +1, filedata.length() -1);
	}

	return 0;
}

int RetrieveHeaderFromFile(const char *fileName, char ** header)
{
	FILE * fp = fopen(fileName, "rb");
	if (NULL == fp)
		return -1;

	long fLen = 0;
	get_FileSize(fp, &fLen);
	*header = (char*)malloc(fLen +1);
	(*header)[fLen] = 0;
	fread(*header, 1, fLen, fp);
	fclose(fp);

	return 0;
}

int ParseDirectoryTree(const char *Path, const char *headerFile, bool recur = FALSE)
{
  int Status = 0, pos = -1;
  HANDLE FileHandle = {0};
  WIN32_FIND_DATA FileData = {0};
  char FullPath[MAX_PATH] = {0};
  char SubDirPath[MAX_PATH] = {0};

  // sprintf(FullPath, "%s\\*.txt", Path);
  strcpy(FullPath, Path);
  fprintf(stderr, "Checking path %s\n", FullPath);

  FileHandle = FindFirstFile(FullPath, &FileData);

	if(INVALID_HANDLE_VALUE == FileHandle) {
		printf("Error in FindFirstFile for %s\n", FullPath);
	} else {
		char * header = NULL;
		if (FALSE == NOHEADER) {
			Status = RetrieveHeaderFromFile(headerFile, &header);
			if (Status != 0) {
				PrintHelp();
				return Status;
			}
		}

		do {
			if(strcmp(FileData.cFileName, ".") != 0 && strcmp(FileData.cFileName, "..") != 0) {
				if(FileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
					sprintf(SubDirPath, "%s%s", FullPath, FileData.cFileName);
					if (TRUE == recur) {
					//  do we care? ... naaah not really unless
					//					we get a hugh amount of money
					//	Status = ParseDirectoryTree(SubDirPath, headerFile, recur);
					}
				} else {
					char showMe[MAX_PATH];
					strcpy(showMe, Path);
					std::string s = showMe;
					while (	-1 < (pos = s.find_last_of("\\")) ) {
						if (pos < s.length() -1)
							s = s.substr(0, s.length() -1);
						else
							break;
					}
					strcpy(showMe, s.c_str());
					strcat(showMe, FileData.cFileName);

					FILE * fp = NULL;
					char * data = NULL;

					fp = fopen(showMe, "rb");
					if (NULL != fp) {
						long size = 0;
						get_FileSize(fp, &size);
						data = (char*)malloc(size +1);
						data[size] = 0;
						fread(data, 1, size, fp);
						fclose(fp);
						fp = NULL;
					}

					fp = fopen(showMe, "w+b");
					if (NULL != fp && NULL != data) {
						long size = 0;
						char * complete = NULL;
						get_FileSize(fp, &size);

						if (NOHEADER == FALSE) {
							if (NULL == header)
								return -1;

							// add header
							complete = (char*)malloc(strlen(header) + strlen(data) +1);
							complete[strlen(header) + strlen(data)] = 0;
							strcpy(complete, header);
							strcat(complete, data);
						} else {
							complete = (char*)malloc(strlen(data) +1);
							complete[strlen(data)] = 0;
							strcpy(complete, data);
						}

						std::string completeBef = complete;
						free(complete);

						if (!names.empty() && names.size() == values.size()) {
							std::list<std::string>::iterator iteV;
							std::list<std::string>::iterator ite;
							ite = names.begin(); iteV = values.begin();
							while (ite != names.end() && iteV != names.end()) {
								std::string srcWord;
								std::string item = *ite;

								srcWord  = "$";
								srcWord += item;
								srcWord += ":";

								std::string value = *iteV;

								int ediPos = -1;
								if (-1 < (ediPos = completeBef.find(srcWord))) {
									std::string first, last, middle;

									first = completeBef.substr(0, ediPos + srcWord.length());
									last = completeBef.substr(ediPos + srcWord.length(), completeBef.length()-1);
									last = last.substr(last.find("$"), last.length()-1);

									first += " ";
									first += value;
									first += last;
									completeBef = first;
								}

								ite++; iteV++;
							}
						}

						complete = (char*)malloc(completeBef.length()+1);
						complete[completeBef.length()] = 0;
						strcpy(complete, completeBef.c_str());

						// writes edited file to disk
						fwrite(complete, 1, strlen(complete), fp);
						fclose(fp);

						free(complete);
						free(data);
					}
				}
			}
		} while(FindNextFile(FileHandle, &FileData));

		free(header);
		FindClose(FileHandle);
	}

	return Status;
}

std::string rightTrim(std::string in)
{
	int pos = -1;
	while (" " == in.substr(in.length() -1, in.length())) {
		in = in.substr(0, in.length() -1);
	}
	return in;
}

int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow)
{
	names.clear();
	values.clear();

	bool recursive = FALSE;
	int pos = -1;
	char * cmdL = GetCommandLine();
	std::string s = cmdL;

	pos = s.find("-help");
	if (-1 < pos) {
		PrintHelp();
		return 0;
	}
	pos = s.find("-basedir");
	if (-1 == pos) {
		PrintHelp();
		return 0;
	}

	std::string base;
	base = s.substr(pos, s.length());
	base = base.substr(9, base.length());
	while ( -1 < (pos = base.find("-"))) {
		base = base.substr(0, base.length() -1);
	}
	base = rightTrim(base);

	pos = s.find("-headerdir");
	if (-1 == pos) {
		PrintHelp();
		return 0;
	}

	std::string header;
	header = s.substr(pos, s.length());
	header = header.substr(11, header.length());
	while ( -1 < (pos = header.find("-"))) {
		header = header.substr(0, header.length() -1);
	}
	header = rightTrim(header);

	if ("noheader" == header) {
		NOHEADER = TRUE;
	}

	pos = s.find("-r");
	if (-1 < pos) {
		recursive = TRUE;
	}

	pos = s.find("-params");
	if (-1 < pos) {
		std::string params;
		params = s.substr(pos, s.length());
		params = params.substr(8, params.length());
		while ( -1 < (pos = params.find("-"))) {
			params = params.substr(0, params.length() -1);
		}
		params = rightTrim(params);

		ParseParameters(params.c_str());
	}

	ParseDirectoryTree(base.c_str(), header.c_str(), recursive);

	return 0;
}
